package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.api.RemoteNoteService;
import cn.wolfcode.wolf2w.api.RemoteQuestionService;
import cn.wolfcode.wolf2w.api.RemoteStrategyService;
import cn.wolfcode.wolf2w.api.domain.Destination;
import cn.wolfcode.wolf2w.api.domain.Note;
import cn.wolfcode.wolf2w.api.domain.Strategy;
import cn.wolfcode.wolf2w.business.query.SearchQuery;
import cn.wolfcode.wolf2w.business.service.ISearchService;
import cn.wolfcode.wolf2w.member.api.RemoteUserInfoService;
import cn.wolfcode.wolf2w.member.api.domain.UserInfo;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 浪兎兎
 * @since 2025/6/13 10:00
 */
@Service
public class SearchServiceImpl<T, E> implements ISearchService {

    @Autowired
    private ElasticsearchRestTemplate template;
    @Autowired
    private RemoteStrategyService strategyService;
    @Autowired
    private RemoteDestinationService destinationService;
    @Autowired
    private RemoteQuestionService questionService;
    @Autowired
    private RemoteUserInfoService userInfoService;
    @Autowired
    private RemoteNoteService noteService;


    @Override
    public <T, E> Page<T> searchHighlight(Class<T> clazz, Class<E> esClazz, SearchQuery qo, String... fields) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 构造分页条件
        PageRequest pageRequest = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize());
        // 构造高亮条件
        List<HighlightBuilder.Field> collect = Arrays.stream(fields).map(field -> {
            HighlightBuilder.Field highlightField = new HighlightBuilder.Field(field);
            highlightField.preTags("<span style=\"color:red\">");
            highlightField.postTags("</span>");
            return highlightField;
        }).collect(Collectors.toList());
        // 检索
        builder.withQuery(
                        QueryBuilders.multiMatchQuery(qo.getKeyword(), fields)
                )
                .withPageable(pageRequest)
                .withHighlightFields(collect);
        SearchHits<E> search = template.search(builder.build(), esClazz);
        // 总条数
        long total = search.getTotalHits();
        List<T> resultList = search.stream().map(hit -> {
            // 从 MySQL 查询
            Long id = Long.valueOf(Objects.requireNonNull(hit.getId()));
            T obj = null;
            switch (qo.getType()) {
                case 0:
                    obj = (T) destinationService.getOne(id, "inner").getData();
                    break;
                case 1:
                    obj = (T) strategyService.getOne(id, "inner").getData();
                    break;
                case 2:
                    obj = (T) noteService.getOne(id, "inner").getData();
                    break;
                case 3:
                    obj = (T) userInfoService.getOne(id, "inner").getData();
                    break;
                case 4:
                    obj = (T) questionService.getOne(id, "inner").getData();
                    break;
                default:
                    if (clazz == Strategy.class) {
                        obj = (T) strategyService.getOne(id, "inner").getData();
                    } else if (clazz == Note.class) {
                        obj = (T) noteService.getOne(id, "inner").getData();
                    } else if (clazz == UserInfo.class) {
                        obj = (T) userInfoService.getOne(id, "inner").getData();
                    } else if (clazz == Destination.class) {
                        obj = (T) destinationService.getOne(id, "inner").getData();
                    } else if (clazz == QuestionSearchServiceImpl.class) {
                        obj = (T) questionService.getOne(id, "inner").getData();
                    }
            }
            if (obj == null) {
                return null;
            }
            // 设置高亮
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            T finalObj = obj;
            highlightFields.forEach((k, v) -> {
                StringBuffer sb = new StringBuffer();
                v.forEach(sb::append);
                try {
                    BeanUtils.setProperty(finalObj, k, sb.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            return obj;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        return new PageImpl<>(resultList, pageRequest, total);
    }
}
